<?php
/**
 * PsiFramework
 *
 * Php Simple Framework
 *
 * PHP version 5.3
 *
 * @category  PsiFramework.Plugins.Form.Classes.DAO
 * @package   PsiFramework.Plugins.Form.Classes.DAO
 * @author    Remi San <remi.san@gmail.com>
 * @copyright 2011 Remi San
 * @license   http://creativecommons.org/licenses/by/3.0/  Creative Commons CC BY 3.0
 * @version   SVN: <svn_id>
 * @link      http://www.psiframework.com/phpdoc/classes/db_\PsiFramework\Plugins\Form\Classes\DAO\FormResponseDAO.html
 */

namespace PsiFramework\Plugins\Form\Classes\DAO;

import("Classes.DAO.AbstractDAO");
import("Plugins.Form.Classes.Model.FormResponse");
import("Classes.Factory.DAOFactory");
import("Plugins.Form.Classes.DAO.FieldTypeDAO");
import("Classes.Util.Manager.PluginManager");

use \PsiFramework\Classes\DAO\AbstractDAO;
use \PsiFramework\Classes\Model\Object;
use \PsiFramework\Classes\Factory\DAOFactory;
use \PsiFramework\Classes\Util\Database\Filters\QueryFilter;
use \PsiFramework\Classes\Util\Database\Query\SqlColumn;
use \PsiFramework\Classes\Util\Database\Query\SqlOperation;
use \PsiFramework\Classes\Util\Database\Query\SqlValue;
use \PsiFramework\Classes\Util\Manager\PluginManager;
use \PsiFramework\Classes\Util\Object\Date;
use \PsiFramework\Classes\Util\Parameters\ObjectParameters;
use \PsiFramework\Classes\Util\Parameters\Object\Operations\Elements\OperationColumn;
use \PsiFramework\Classes\Util\Parameters\Object\Operations\Elements\OperationValue;
use \PsiFramework\Plugins\Form\Classes\DAO\FieldTypeDAO;
use \PsiFramework\Plugins\Form\Classes\Model\FormResponse;
use \PsiFramework\Plugins\Form\Classes\Util\Json\JsonForm;
use \PsiFramework\Plugins\Form\Classes\Util\Json\Elements\JsonFormInput;


/**
 * The FormResponse Data Access Object
 *
 * This is the default class for the FormResponse Data Access Object
 *
 * @category PsiFramework.Plugins.Form.Classes.DAO
 * @package  PsiFramework.Plugins.Form.Classes.DAO
 * @author   Remi San <remi.san@gmail.com>
 * @license  http://creativecommons.org/licenses/by/3.0/  Creative Commons CC BY 3.0
 * @link     http://www.psiframework.com/phpdoc/classes/db_\PsiFramework\Plugins\Form\Classes\DAO\FormResponseDAO.html
 */
class FormResponseDAO extends AbstractDAO
{
    /**
     * @var FormResponseDAO
     */
    protected static $_singleton = array();

    /**
     * FormResponseDAO constructor
     *
     * @param ObjectParameters $objectParameters The object parameters
     *
     * @return FormResponseDAO
     */
    protected function __construct(ObjectParameters $objectParameters)
    {

        if (is_null($objectParameters)) {
            throw new \Exception(
                "Object Parameters must be passed to ".
                "the FormResponseDAO constructor !"
            );
        }

        parent::__construct($objectParameters);

        $pluginManager = PluginManager::getInstance();
        $formPlugin = $pluginManager->getPlugin("Form");

        if (!$formPlugin->isObjectParametersRetrieved()) {

            $fieldTypeDao = DAOFactory::getDAO("FieldType");
            $types = $fieldTypeDao->retrieveAll();

            foreach ($types as $type) {
                $rp = $type->getResponseParameters();
                if (!is_null($rp)) {
                    $formPlugin->addObjectParameter($rp);
                }
            }

            $formDao = DAOFactory::getDAO("Form");
            $forms = $formDao->retrieveAll();

            foreach ($forms as $form) {
                $rp = $form->getResponseParameters();
                if (!is_null($rp)) {
                    $formPlugin->addObjectParameter($rp);
                }
            }
            
            $formPlugin->setObjectParametersRetrieved(true);
        }

        $formPlugin->addObjectParameter($objectParameters);
    }

    /**
     * The function to save a FormResponse
     *
     * @param FormResponse &$object            The object to save
     * @param bool         $performTransaction Does the save action
     *                                         need a transaction ?
     * @param bool         $checkSecurity      Does the save action
     *                                         need to checkthe security ?
     *
     * @see AbstractDAO::save()
     *
     * @return bool
     */
    public function save(
        Object   &$object,
        /*bool*/ $performTransaction=true,
        /*bool*/ $checkSecurity=true
    )
    {

        if ($performTransaction) {
            $this->_database->startTransaction();
        }

        if (is_null($object->getModificationDate())) {
            $object->setModificationDate(Date::now());
        }

        $ok = parent::save($object, false, $checkSecurity);

        if ($performTransaction) {
            if ($ok) {
                $this->_database->commit();
            } else {
                $this->_database->rollback();
            }
        }
    }

    /**
     * The function to Retrieve the object using its primary key
     *
     * @param mixed $key                 The key of the object
     * @param bool  $forceReloadFromBase Force the sql query ?
     * @param bool  $checkSecurity       Does the retrieve action
     *                                   need to check the security ?
     * @param IUser $user                The user to filter
     * @param Form  $form                The form to filter
     *
     * @return ResponseDAO
     */
    public function retrieveByPk(
        /*mixed*/ $key,
        /*bool*/  $forceReloadFromBase=false,
        /*bool*/  $checkSecurity=true,
        /*IUser*/ $user=null,
        /*Form*/  $form=null
    )
    {
        $obj = parent::retrieveByPk($key, $forceReloadFromBase, $checkSecurity);
        
        if (is_null($obj)
            && $this->_objectParameters->isView()
            && !is_null($user)
            && !is_null($form)
        ) {
            //On vérifie si aucun objet n'a été retourné
            //à cause d'une jointure manquante

            $constructionOperation
                = $this->_objectParameters->getConstructionOperation();
            $id = $key ;

            $fieldIds = array();
            $wc = $constructionOperation->getWhereClause();
            foreach ($wc->getElements() as $clause) {
                if ($clause->getType() == '=') {
                    $column = $clause->getElement(0);
                    if ($column instanceof OperationColumn
                        && $column->getName() == 'field'
                    ) {
                        $value = $clause->getElement(1);
                        if ($value instanceof OperationValue) {
                            $objectAlias = $column->getObject()->getAlias();
                            $fieldIds[$objectAlias] = $value->getValue();
                        }
                    }
                }
            }

            $notFound = array();
            foreach ($constructionOperation->getObjects() as $object) {
                $frDao = DAOFactory::getDAO($object->getName());
                $fieldId = $fieldIds[$object->getAlias()] ;
                $newKey = array(
                    'formResponseId'=>$id,
                    'user'=>$user->getId(),
                    'form'=>$form->getId(),
                    'field'=>$fieldId
                );
                $resp = $frDao->retrieveByPk(
                    $newKey,
                    $forceReloadFromBase,
                    $checkSecurity
                );
                if (is_null($resp)) {
                    $notFound[] = $object ;
                }
            }

            if (count($notFound)>0
                && count($notFound)!=count($constructionOperation->getObjects())
            ) {
                $fieldDao = DAOFactory::getDAO('FormField');

                foreach ($notFound as $object) {

                    $fieldId = $fieldIds[$object->getAlias()] ;
                    $field = $fieldDao->retrieveByPk($fieldId);

                    if (!is_null($field)) {
                        $frDao = DAOFactory::getDAO($object->getName());

                        $resp = $frDao->getEmptyObject();
                        $resp->setId($id);
                        $resp->setUser($user);
                        $resp->setForm($form);
                        $resp->setField($field);
                        $resp->setModificationDate(Date::now());

                        $frDao->save($resp);
                    }
                }

                $obj = parent::retrieveByPk(
                    $key,
                    $forceReloadFromBase,
                    $checkSecurity
                );
            }
        }

        return $obj ;
    }

    /**
     * The function that retrives the FormResponses for the specified IUser
     * 
     * @param IUser $user The user used to filter the results
     * 
     * @return array
     */
    public function retrieveByUser(/*IUser*/ $user)
    {

        if (is_null($user)) {
            return array();
        }

        $colUser = new SqlColumn("user_id");
        $sqlValue = new SqlValue($user->getId());

        $op = new SqlOperation(SqlOperation::$equal);
        $op->addParameter($colUser);
        $op->addParameter($sqlValue);

        return $this->retrieveAll(new QueryFilter($op));

    }

    /**
     * The function that indiciates if the Formresponse is empty
     * 
     * @param JsonForm         $form               The Form
     * @param ObjectParameters $responseParameters The ObjectParameters
     * @param FormResponse     $response           The FormResponse
     * 
     * @return bool
     */
    public function isEmpty(
        JsonForm         $form,
        ObjectParameters $responseParameters,
        /*FormResponse*/ $response
    )
    {

        $empty = true ;

        if (!is_null($response)) {
            $elements = $form->getElements();

            if (!is_null($elements)) {
                foreach ($elements as $field) {
                    foreach ($field->getElements() as $element) {

                        $inputElement = '' ;

                        if ($element instanceof JsonFormInput) {

                            $value = null ;
                            $param = $responseParameters->getParameter(
                                $element->getName()
                            );
                            if (!is_null($param)) {
                                $getter = $param->getter ;
                                $value = $response->{$getter}();
                            }
                            if (!isNullOrEmptyString($value)
                                && $element->getInputType() == 'checkbox'
                            ) {
                                if (strpos($value, ',')>0) {
                                    $value = preg_split("[,]", $value);
                                }
                            }

                            if (!isNullOrEmptyString($value)
                                || (is_array($value) && count($value)>0)
                            ) {
                                $empty = false ;
                                break;
                            }
                        }
                    }
                }
            }
        }

        return $empty ;
    }

    /**
     * The function to call instead of the constructor.
     *
     * @param ObjectParameters $objectParameters The object parameters
     *                                           for FormFieldLink
     *
     * @return FormResponseDAO
     */
    public static function getInstance(ObjectParameters $objectParameters)
    {

        $name = $objectParameters->getName();

        if (!isset(self::$_singleton[$name])) {
            self::$_singleton[$name] = new FormResponseDAO($objectParameters);
        }

        return self::$_singleton[$name];
    }
}
